import { HttpException, HttpStatus, Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Like, MongoRepository } from "typeorm";
import { Devices } from "./entities/device.entity";
import { handlePageing } from "../utils/index";

@Injectable()
export class DeviceService {
  constructor(@InjectRepository(Devices) private deviceRep: MongoRepository<Devices>) {}

  // * 创建单个设备数据
  async create(params: { name: string; serialNumber: string; unit: string }) {
    if (!params.name || !params.serialNumber || !params.unit) {
      throw new HttpException("参数不正确", HttpStatus.BAD_REQUEST);
    }
    // * typeorm 操作 mongodb ,不适用于 create 方法,因为 create 之后 还是需要 save
    // * 但是 如果有设置默认值 必须用 create 方法在 save , 这样才能设置默认值
    const createData = await this.deviceRep.create(params);
    const result = await this.deviceRep.save(createData);
    return result;
  }
  // 查询所有设备数据
  async findAll({ pageNum, pageSize, order, name }) {
    // 排序 默认降序 (也就是最新创建时间)
    let options = { order: { createTime: order || "DESC" } };
    // 分页
    options = { ...options, ...handlePageing({ pageNum, pageSize }) };
    if (name) {
      // options["where"] = { name: Like(`%${name}%`) }; // 匹配包含关键字的任意位置的记录
      options["where"] = { name: new RegExp(`${name}`) }; // * typeorm 对 mongodb 支持度不够 必须使用这种方法才能查询
    }
    // find-查找全部   findAndCount-返回数据和总的条数
    const [data, total] = await this.deviceRep.findAndCount(options);
    return { data, total, pageNum: +pageNum || 1, pageSize: +pageSize || 10 };
  }
  // * 查询单个设备数据
  async findOne(id) {
    if (!id) {
      throw new HttpException("id不能为空", HttpStatus.BAD_REQUEST);
    }
    // return await this.deviceRep.find({ id }); // 找不到返回空对象
    // return await this.deviceRep.find({ where: { id } }); // 找不到返回空对象
    // return await this.deviceRep.findOne(id); // * typeorm 操作mongodb 禁止这样 会报错
    return await this.deviceRep.findOne({ where: { id } }); // 找不到返回undefined
  }
  // * 更新单个设备数据
  async update(source) {
    const result = await this.deviceRep.findOne({ where: { id: source.id } });
    if (!result) {
      throw new HttpException("当前无此设备", HttpStatus.NOT_FOUND);
    }
    // 置空 只记录一次修改的值
    result.changeFields = [];
    // 观察哪些字段进行了更改
    const watchFieldChange = field => {
      // 如果值不相同 则重新赋值
      if (source[field] !== result[field]) {
        result[field] = source[field];
        result.changeFields.push(field);
        result.updateTime = new Date();
      }
    };
    const fields = ["name", "serialNumber", "unit"];
    fields.forEach(item => watchFieldChange(item));

    // * save 方法会返回更新后的实体  update 返回的我也不知道是啥
    // return await this.deviceRep.save(result);

    // ERROR [ExceptionsHandler] Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer  注意这里需要用 mongodb的ObjectId,也就是_id
    await this.deviceRep.update(result._id, result);
    return result;
  }
  // * 删除单个设备数据
  async removeOne(id: string) {
    if (!id) {
      throw new HttpException("id不能为空", HttpStatus.BAD_REQUEST);
    }
    const result = await this.deviceRep.findOne({ where: { id } });
    if (!result) {
      throw new HttpException("当前无此设备", HttpStatus.NOT_FOUND);
    }
    // remove能够触发subscriber、entity listener。而delete方法不能触发，这类似于save与insert、update的关系
    await this.deviceRep.remove(result);
    // await this.deviceRep.delete(result);
    return {};
  }
  // * 删除多个设备数据
  async removeMany(ids: string[]) {
    if (!Array.isArray || !ids?.length) {
      throw new HttpException("参数不能为空", HttpStatus.BAD_REQUEST);
    }
    // mongodb 中 id 必须是 _id
    const result = await this.deviceRep.find({ where: { id: { $in: ids } } });
    const currentIds = result.map(item => item._id);
    if (Array.isArray(result) && result?.length) {
      // remove 不能这样 返回格式不一样
      const res = await this.deviceRep.delete(currentIds);
      const handleReturnData = () => {
        let returnObj = {};
        if (res?.raw?.length) {
          for (let i = 0, len = res.raw.length; i < len; i++) {
            const item = res.raw[i];
            const currentId = ids[i];
            if (item.deletedCount === 0) {
              returnObj[currentId] = `id ${currentId} 删除失败`;
            }
          }
        }
        return returnObj;
      };
      return handleReturnData();
    } else {
      throw new HttpException("参数异常", HttpStatus.NOT_FOUND);
    }
  }
}
